package com.dms.modules.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dms.common.exception.BusinessException;
import com.dms.modules.user.dto.UserBehaviorDTO;
import com.dms.modules.user.entity.UserBehaviorStats;
import com.dms.modules.user.entity.UserFavorite;
import com.dms.modules.user.entity.UserSearchHistory;
import com.dms.modules.user.mapper.UserBehaviorStatsMapper;
import com.dms.modules.user.mapper.UserBehaviorMapper;
import com.dms.modules.user.mapper.UserFavoriteMapper;
import com.dms.modules.user.mapper.UserSearchHistoryMapper;
import com.dms.modules.user.service.UserBehaviorService;
import com.dms.modules.user.service.UserFavoriteService;
import com.dms.modules.product.mapper.ProductMapper;
import com.dms.modules.product.entity.Product;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Value;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserBehaviorServiceImpl extends ServiceImpl<UserBehaviorStatsMapper, UserBehaviorStats> implements UserBehaviorService {

    private static final String FAVORITE_CACHE_PREFIX = "user:favorite:";
    private static final String BROWSE_HISTORY_CACHE_PREFIX = "user:browse:";

    @Autowired
    @Lazy
    private UserFavoriteService userFavoriteService;

    @Autowired
    private UserBehaviorMapper userBehaviorMapper;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private UserFavoriteMapper favoriteMapper;

    @Autowired
    private UserSearchHistoryMapper userSearchHistoryMapper;

    @Value("${app.search.max-history-size:100}")
    private int maxHistorySize;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean recordUserBrowse(Long userId, UserBehaviorDTO dto) {
        if (userId == null || dto == null || dto.getProductId() == null) {
            throw new BusinessException("参数不能为空");
        }
        return recordBehavior(userId, BehaviorType.BROWSE, dto.getProductId().toString());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean recordBehavior(Long userId, BehaviorType type, String content) {
        try {
            UserBehaviorStats stats = new UserBehaviorStats();
            stats.setUserId(userId);
            stats.setBehaviorType(type.name());
            stats.setCount(1);
            stats.setLastTime(LocalDateTime.now());
            
            if (type == BehaviorType.BROWSE && content != null) {
                try {
                    Long productId = Long.parseLong(content);
                    Product product = productMapper.selectById(productId);
                    if (product != null) {
                        stats.setCategoryId(product.getCategoryId());
                    }
                } catch (Exception ignored) {}
            }

            // 查询现有记录
            QueryWrapper<UserBehaviorStats> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId)
                       .eq("behavior_type", type.name());
            if (stats.getCategoryId() != null) {
                queryWrapper.eq("category_id", stats.getCategoryId());
            }

            UserBehaviorStats existingStats = getBaseMapper().selectOne(queryWrapper);
            
            if (existingStats != null) {
                // 更新现有记录
                UserBehaviorStats updateStats = new UserBehaviorStats();
                updateStats.setCount(existingStats.getCount() + 1);
                updateStats.setLastTime(LocalDateTime.now());
                return getBaseMapper().update(updateStats, 
                    new QueryWrapper<UserBehaviorStats>().eq("id", existingStats.getId())) > 0;
            } else {
                // 插入新记录
                return save(stats);
            }
        } catch (Exception e) {
            log.error("记录用户行为失败: userId={}, type={}", userId, type, e);
            throw new BusinessException("记录用户行为失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recordUserSearch(Long userId, String keyword) {
        if (userId == null || StringUtils.isBlank(keyword)) {
            throw new BusinessException("参数不能为空");
        }

        keyword = keyword.trim();
        LocalDateTime now = LocalDateTime.now();
        
        try {
            // 查询记录（包括已删除的）
            UserSearchHistory existingRecord = userSearchHistoryMapper.selectOne(
                new QueryWrapper<UserSearchHistory>()
                    .eq("user_id", userId)
                    .eq("keyword", keyword)
            );
            
            if (existingRecord != null) {
                // 更新记录
                UserSearchHistory updateRecord = new UserSearchHistory();
                updateRecord.setId(existingRecord.getId());
                updateRecord.setSearchCount(existingRecord.getSearchCount() + 1);
                updateRecord.setLastSearchTime(now);
                updateRecord.setDeleted(0);  // 重新激活
                userSearchHistoryMapper.updateById(updateRecord);
            } else {
                // 创建新记录
                UserSearchHistory newRecord = new UserSearchHistory();
                newRecord.setUserId(userId);
                newRecord.setKeyword(keyword);
                newRecord.setSearchCount(1);
                newRecord.setFirstSearchTime(now);
                newRecord.setLastSearchTime(now);
                userSearchHistoryMapper.insert(newRecord);
            }

            // 更新行为统计
            recordBehavior(userId, BehaviorType.SEARCH, keyword);
        } catch (Exception e) {
            log.error("记录搜索历史失败: userId={}, keyword={}", userId, keyword, e);
            throw new BusinessException("记录搜索历史失败");
        }
    }

    @Override
    public List<Map<String, Object>> getUserBehaviorHistory(Long userId, String behaviorType, 
                                                          LocalDateTime startTime, LocalDateTime endTime) {
        LambdaQueryWrapper<UserBehaviorStats> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserBehaviorStats::getUserId, userId);
        if (behaviorType != null) {
            wrapper.eq(UserBehaviorStats::getBehaviorType, behaviorType);
        }
        if (startTime != null) {
            wrapper.ge(UserBehaviorStats::getCreateTime, startTime);
        }
        if (endTime != null) {
            wrapper.le(UserBehaviorStats::getCreateTime, endTime);
        }
        wrapper.orderByDesc(UserBehaviorStats::getCreateTime);
        
        List<UserBehaviorStats> stats = list(wrapper);
        return stats.stream().map(stat -> {
            Map<String, Object> map = new HashMap<>();
            map.put("userId", stat.getUserId());
            map.put("behaviorType", stat.getBehaviorType());
            map.put("count", stat.getCount());
            map.put("createTime", stat.getCreateTime());
            return map;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Map<String, Object>> getUserCategoryPreferences(Long userId, Integer limit) {
        LambdaQueryWrapper<UserBehaviorStats> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserBehaviorStats::getUserId, userId)
                .isNotNull(UserBehaviorStats::getCategoryId)
                .orderByDesc(UserBehaviorStats::getCount);
        
        if (limit != null) {
            wrapper.last("LIMIT " + limit);
        }
        
        List<UserBehaviorStats> stats = list(wrapper);
        return stats.stream().map(stat -> {
            Map<String, Object> map = new HashMap<>();
            map.put("categoryId", stat.getCategoryId());
            map.put("count", stat.getCount());
            return map;
        }).collect(Collectors.toList());
    }

    @Override
    public Set<Long> getUserProductIds(Long userId) {
        Set<Long> productIds = new HashSet<>();
        
        // 获取用户浏览历史中的商品ID
        List<Map<String, Object>> browseHistory = getUserBehaviorHistory(userId, "BROWSE", null, null);
        browseHistory.forEach(history -> {
            try {
                Long productId = Long.parseLong((String) history.get("content"));
                productIds.add(productId);
            } catch (Exception e) {
                // 忽略解析错误
            }
        });
        
        return productIds;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean clearUserBehaviorHistory(Long userId, String behaviorType) {
        LambdaQueryWrapper<UserBehaviorStats> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserBehaviorStats::getUserId, userId);
        if (behaviorType != null) {
            wrapper.eq(UserBehaviorStats::getBehaviorType, behaviorType);
        }
        return remove(wrapper);
    }

    @Override
    public UserBehaviorStats getBehaviorStats(Long userId) {
        if (userId == null) {
            return null;
        }

        // 创建新的统计对象
        UserBehaviorStats result = new UserBehaviorStats();
        result.setUserId(userId);

        // 获取所有行为记录
        LambdaQueryWrapper<UserBehaviorStats> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserBehaviorStats::getUserId, userId);
        List<UserBehaviorStats> statsList = list(wrapper);

        // 统计各类行为数据
        for (UserBehaviorStats stats : statsList) {
            if (stats.getBehaviorType() != null) {
                switch (stats.getBehaviorType()) {
                    case "BROWSE":
                        // 累加浏览次数
                        result.setCount(result.getCount() == null ? stats.getCount() : 
                            result.getCount() + stats.getCount());
                        break;
                    case "SEARCH":
                        // 记录搜索次数
                        result.setBehaviorType("SEARCH");
                        break;
                    // 可以添加其他行为类型的处理
                }
            }
            
            // 更新创建时间和更新时间
            if (result.getCreateTime() == null || 
                (stats.getCreateTime() != null && stats.getCreateTime().isBefore(result.getCreateTime()))) {
                result.setCreateTime(stats.getCreateTime());
            }
            if (result.getUpdateTime() == null || 
                (stats.getUpdateTime() != null && stats.getUpdateTime().isAfter(result.getUpdateTime()))) {
                result.setUpdateTime(stats.getUpdateTime());
            }
        }

        return result;
    }

    @Override
    public Map<String, Integer> getBehaviorTrend(Long userId, BehaviorType type, int days) {
        Map<String, Integer> trend = new HashMap<>();
        LocalDateTime endTime = LocalDateTime.now();
        LocalDateTime startTime = endTime.minusDays(days);
        
        List<UserBehaviorStats> stats = lambdaQuery()
                .eq(UserBehaviorStats::getUserId, userId)
                .eq(UserBehaviorStats::getBehaviorType, type.name())
                .between(UserBehaviorStats::getCreateTime, startTime, endTime)
                .list();
        
        for (UserBehaviorStats stat : stats) {
            String date = stat.getCreateTime().toLocalDate().toString();
            trend.put(date, stat.getCount());
        }
        
        return trend;
    }

    @Override
    public Map<String, Map<String, Integer>> getBehaviorHeatmap(Long userId, BehaviorType type) {
        Map<String, Map<String, Integer>> heatmap = new HashMap<>();
        
        List<UserBehaviorStats> stats = lambdaQuery()
                .eq(UserBehaviorStats::getUserId, userId)
                .eq(UserBehaviorStats::getBehaviorType, type.name())
                .list();
        
        for (UserBehaviorStats stat : stats) {
            String date = stat.getCreateTime().toLocalDate().toString();
            String hour = String.valueOf(stat.getCreateTime().getHour());
            
            heatmap.computeIfAbsent(date, k -> new HashMap<>())
                   .merge(hour, stat.getCount(), Integer::sum);
        }
        
        return heatmap;
    }

    @Override
    public Map<String, Object> analyzeBehaviorPattern(Long userId) {
        Map<String, Object> pattern = new HashMap<>();
        
        // 获取用户行为统计
        UserBehaviorStats stats = getBehaviorStats(userId);
        if (stats != null) {
            pattern.put("totalBehaviors", stats.getCount());
            pattern.put("lastBehaviorTime", stats.getCreateTime());
        }
        
        // 获取用户分类偏好
        List<Map<String, Object>> preferences = getUserCategoryPreferences(userId, 5);
        pattern.put("categoryPreferences", preferences);
        
        return pattern;
    }

    @Override
    public List<Map<String, Object>> getBehaviorRecommendations(Long userId) {
        List<Map<String, Object>> recommendations = new ArrayList<>();
        
        // 获取用户分类偏好
        List<Map<String, Object>> preferences = getUserCategoryPreferences(userId, 5);
        recommendations.addAll(preferences);
        
        // 获取用户行为历史
        List<Map<String, Object>> history = getUserBehaviorHistory(userId, null, null, null);
        recommendations.addAll(history);
        
        return recommendations;
    }

    @Override
    public List<Map<String, Object>> getUserFavorites(Long userId) {
        List<com.dms.modules.user.entity.UserFavorite> favorites = userFavoriteService.lambdaQuery()
                .eq(com.dms.modules.user.entity.UserFavorite::getUserId, userId)
                .eq(com.dms.modules.user.entity.UserFavorite::getDeleted, 0)
                .orderByDesc(com.dms.modules.user.entity.UserFavorite::getCreateTime)
                .list();
        return favorites.stream().map(fav -> {
            Map<String, Object> map = new HashMap<>();
            map.put("id", fav.getId());
            map.put("userId", fav.getUserId());
            map.put("productId", fav.getTargetId());
            map.put("type", fav.getType());
            map.put("createTime", fav.getCreateTime());
            return map;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Map<String, Object>> getUserBrowseHistory(Long userId) {
        LambdaQueryWrapper<UserBehaviorStats> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserBehaviorStats::getUserId, userId)
               .eq(UserBehaviorStats::getBehaviorType, BehaviorType.BROWSE.name())
               .orderByDesc(UserBehaviorStats::getLastTime);
        List<UserBehaviorStats> stats = list(wrapper);
        return stats.stream().map(stat -> {
            Map<String, Object> map = new HashMap<>();
            map.put("id", stat.getId());
            map.put("userId", stat.getUserId());
            map.put("productId", stat.getCategoryId());
            map.put("categoryId", stat.getCategoryId());
            map.put("lastTime", stat.getLastTime());
            map.put("count", stat.getCount());
            return map;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Long> getFavoriteProductIds(Long userId) {
        if (userId == null) {
            return Collections.emptyList();
        }
        
        // 从Redis缓存中获取
        String cacheKey = FAVORITE_CACHE_PREFIX + userId;
        List<Long> cachedIds = (List<Long>) redisTemplate.opsForValue().get(cacheKey);
        if (cachedIds != null) {
            return cachedIds;
        }
        
        // 从数据库中获取
        List<Long> productIds = favoriteMapper.selectList(
            new LambdaQueryWrapper<UserFavorite>()
                .eq(UserFavorite::getUserId, userId)
                .eq(UserFavorite::getType, "product")
                .select(UserFavorite::getTargetId)
        ).stream()
        .map(UserFavorite::getTargetId)
        .collect(Collectors.toList());
        
        // 缓存结果
        redisTemplate.opsForValue().set(cacheKey, productIds, 1, TimeUnit.HOURS);
        
        return productIds;
    }

    @Override
    public List<String> getUserRecentSearches(Long userId, int limit) {
        if (userId == null) {
            return Collections.emptyList();
        }
        
        return userSearchHistoryMapper.selectList(
            new LambdaQueryWrapper<UserSearchHistory>()
                .eq(UserSearchHistory::getUserId, userId)
                .eq(UserSearchHistory::getDeleted, 0)
                .orderByDesc(UserSearchHistory::getLastSearchTime)
                .last("LIMIT " + limit)
        ).stream()
        .map(UserSearchHistory::getKeyword)
        .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clearUserSearchHistory(Long userId) {
        if (userId == null) {
            throw new BusinessException("用户ID不能为空");
        }

        try {
            LambdaUpdateWrapper<UserSearchHistory> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(UserSearchHistory::getUserId, userId)
                        .eq(UserSearchHistory::getDeleted, 0)
                        .set(UserSearchHistory::getDeleted, 1);
            
            userSearchHistoryMapper.update(null, updateWrapper);
        } catch (Exception e) {
            log.error("清除搜索历史失败: userId={}", userId, e);
            throw new BusinessException("清除搜索历史失败");
        }
    }

    /**
     * 清理过多的搜索历史
     */
    private void cleanupOldSearchHistory(Long userId) {
        try {
            // 获取当前用户的搜索历史数量
            Long count = userSearchHistoryMapper.selectCount(
                new LambdaQueryWrapper<UserSearchHistory>()
                    .eq(UserSearchHistory::getUserId, userId)
                    .eq(UserSearchHistory::getDeleted, 0)
            );

            // 如果超过最大限制，删除最早的记录
            if (count > maxHistorySize) {
                // 获取需要保留的最早的记录的时间
                List<UserSearchHistory> histories = userSearchHistoryMapper.selectList(
                    new LambdaQueryWrapper<UserSearchHistory>()
                        .eq(UserSearchHistory::getUserId, userId)
                        .eq(UserSearchHistory::getDeleted, 0)
                        .orderByDesc(UserSearchHistory::getLastSearchTime)
                        .last("LIMIT " + maxHistorySize)
                );

                if (!histories.isEmpty()) {
                    LocalDateTime cutoffTime = histories.get(histories.size() - 1).getLastSearchTime();
                    
                    // 删除早于截止时间的记录
                    LambdaUpdateWrapper<UserSearchHistory> updateWrapper = new LambdaUpdateWrapper<>();
                    updateWrapper.eq(UserSearchHistory::getUserId, userId)
                                .eq(UserSearchHistory::getDeleted, 0)
                                .lt(UserSearchHistory::getLastSearchTime, cutoffTime)
                                .set(UserSearchHistory::getDeleted, 1);
                    
                    int updated = userSearchHistoryMapper.update(null, updateWrapper);
                    log.info("清理旧搜索历史: userId={}, 清理记录数={}", userId, updated);
                }
            }
        } catch (Exception e) {
            log.warn("清理旧搜索历史失败: userId={}", userId, e);
            // 不抛出异常，让主流程继续
        }
    }
} 